package redisv9ex

import (
	"fmt"
	"gitee.com/ymofen/gobase"
	"gitee.com/ymofen/gobase/factory"
	// "github.com/go-redis/redis/v8"
	redis "github.com/redis/go-redis/v9"
	"runtime"
	"strings"
	"sync/atomic"
)

var (
	redisClientAliveN  int32
	DefaultRedisClient = gobase.NewConnectObjectRefStorage(newRedisClient)
)

func RedisClientAliveN() int32 {
	return atomic.LoadInt32(&redisClientAliveN)
}

// addr=127.0.0.1:9002,127.0.0.1:9003&user=&pass=&conrand=&cluster=1
func newRedisClient(connstr string) interface{} {
	conf := gobase.NewStrMap()
	conf.URLFormDecode(connstr)

	if conf.IntByName("cluster", 0) == 1 {
		str := conf.StringByName("addr", "")
		redisOpt := &redis.ClusterOptions{
			Addrs:    strings.Split(str, ","),
			Password: conf.StringByName("pass", ""),
			Username: conf.StringByName("user", ""),
		}
		c := redis.NewClusterClient(redisOpt)
		atomic.AddInt32(&redisClientAliveN, 1)
		runtime.SetFinalizer(c, func(obj interface{}) {
			atomic.AddInt32(&redisClientAliveN, -1)
		})
		return c
	} else {
		redisOpt := &redis.Options{
			Addr:     conf.StringByName("addr", ""),
			Password: conf.StringByName("pass", ""),
			Username: conf.StringByName("user", ""),
		}
		c := redis.NewClient(redisOpt)
		atomic.AddInt32(&redisClientAliveN, 1)
		runtime.SetFinalizer(c, func(obj interface{}) {
			atomic.AddInt32(&redisClientAliveN, -1)
		})
		return c
	}

}

func checkGetRedisClient(args ...interface{}) (rval interface{}, err error) {
	confMap, ok := args[0].(gobase.StrMap)
	if !ok {
		if str, ok1 := args[0].(string); ok1 {
			confMap = gobase.NewStrMap()
			confMap.URLFormDecode(str)
		}
	}
	if confMap == nil || len(confMap) == 0 {
		return nil, fmt.Errorf("Acquisition failed! invalid args!")
	}
	if _, ok0 := confMap["addr"]; !ok0 {
		if v, ok1 := confMap["connstr"]; ok1 {
			confMap["addr"] = v
		}
	}

	s := confMap.URLEncode0WithKeys("addr", "pass", "user", "connrand", "cluster")
	rval = DefaultRedisClient.CheckGetRef(s)
	return
}

func NewRedisOperatorByObjectInnerRef(obj interface{}) *RedisOperator {
	clt := obj.(*gobase.ObjectInnerRef).GetObject().(redis.Cmdable)
	return NewRedisOperator(clt)
}

func CheckGetRedisClientObjectRef(s string) (rval interface{}, err error) {
	return checkGetRedisClient(s)
}

func FinalRedisOpera(ins *RedisOperator) {
	ins.Close()
}

func NewRedisIns() *gobase.SyncInstance[*RedisOperator] {
	return gobase.NewSyncInstance[*RedisOperator](
		// 直接创建， 不需要class
		gobase.WithCreateFunc[*RedisOperator](CheckGetRedisClientObjectRef),
		gobase.WithInitFunc(NewRedisOperatorByObjectInnerRef),
		gobase.WithFinalFunc(FinalRedisOpera),
	)
}

func init() {
	factory.RegisterCreateFunc("getfrom.instance.redisclt", checkGetRedisClient)
	factory.RegisterCreateFunc("instance.redisclt", checkGetRedisClient)
}
